// -----------------------------------------------------------------------------
// This source file is part of Matrix Platform
// 	(Universal .NET Software Development Platform)
// For the latest info, see http://www.matrixplatform.com
// 
// Copyright (c) 2009-2010, Ingenious Ltd
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Matrix.Common.Core;
using Matrix.Common.Diagnostics.TracerCore;
using Matrix.Common.Diagnostics.TracerCore.Items;
using Matrix.Common.Diagnostics.TracerCore.Sinks;

namespace Matrix.Common.Diagnostics
{
    /// <summary>
    /// This class encorporates tracing, monitoring, verify/debug/assert on system level all together.
    /// The idea is to have all those used from troughout the entire platform in a controlled centralized matter.
    /// Params is prefferable since it can also handle no parameter at all.
    /// </summary>
    public static class SystemMonitor
    {
        static object _syncRoot;

        static readonly SystemVariables _variables = null;

        /// <summary>
        /// System variables.
        /// </summary>
        public static SystemVariables Variables
        {
            get { return _variables; }
        } 

        /// <summary>
        /// Control the global diagnostics mode; when set it 
        /// will not only log, but also raise occuring errors 
        /// and warnings directly to top level attention.
        /// </summary>
        static public bool ShowHighPriorityDebugWarnings { get; set; }

        volatile static Tracer _tracer = null;
        /// <summary>
        /// Default tracer. Assign to make all default static tracing pass trough here.
        /// </summary>
        public static Tracer Tracer
        {
            get { return _tracer; }
        }

        volatile static TracerItemBuilderEx _tracerBuilder;

        #region Events

        public delegate void TracerUpdateDelegate(Tracer tracer);
        public static event TracerUpdateDelegate TracerAssignedEvent;

        #endregion

        /// <summary>
        /// Static constructor.
        /// </summary>
        static SystemMonitor()
        {
            ShowHighPriorityDebugWarnings = false;
            _variables = new SystemVariables();
            _syncRoot = new object();

            CoreSystemMonitor.InfoEvent += new CoreSystemMonitor.ReportDelegate(CoreSystemMonitor_InfoEvent);
            CoreSystemMonitor.ErrorEvent += new CoreSystemMonitor.ReportDelegate(CoreSystemMonitor_ErrorEvent);
            CoreSystemMonitor.OperationErrorEvent += new CoreSystemMonitor.ReportDelegate(CoreSystemMonitor_OperationErrorEvent);
            CoreSystemMonitor.OperationWarningEvent += new CoreSystemMonitor.ReportDelegate(CoreSystemMonitor_OperationWarningEvent);
            CoreSystemMonitor.WarningEvent += new CoreSystemMonitor.ReportDelegate(CoreSystemMonitor_WarningEvent);
        }

        #region Core System Monitor Handling

        static void CoreSystemMonitor_InfoEvent(string details, Exception optionalException)
        {
            Info(details);
        }

        static void CoreSystemMonitor_WarningEvent(string details, Exception optionalException)
        {
            Warning(details);
        }

        static void CoreSystemMonitor_OperationWarningEvent(string details, Exception optionalException)
        {
            OperationWarning(details);
        }

        static void CoreSystemMonitor_OperationErrorEvent(string details, Exception optionalException)
        {
            OperationError(details, optionalException);
        }

        static void CoreSystemMonitor_ErrorEvent(string details, Exception optionalException)
        {
            Error(details, optionalException);
        }

        #endregion

        /// <summary>
        /// Assign the default tracer for the system.
        /// </summary>
        /// <param name="tracer"></param>
        /// <returns></returns>
        public static bool AssignTracer(Tracer tracer)
        {
            lock (_syncRoot)
            {
                if (_tracer != null)
                {
                    return false;
                }

                _tracer = tracer;
            }

            _tracerBuilder = new TracerItemBuilderEx(null);
            _tracerBuilder.ItemCreatedEvent += new TracerItemBuilder.ItemUpdateDelegate(_tracerBuilder_ItemAddedEvent);
            _tracerBuilder.MethodInfoLoopback = 6;
            _tracerBuilder.Tracer = _tracer;

            // Default system trace keeper sink.
            _tracer.Add(new TracerItemKeeperSink(_tracer));

            TracerUpdateDelegate del = TracerAssignedEvent;
            if (del != null)
            {
                del(tracer);
            }

            return true;
        }

        static void _tracerBuilder_ItemAddedEvent(TracerItemBuilder generator, TracerItem item)
        {
            if (ShowHighPriorityDebugWarnings && item.Priority > TracerItem.PriorityEnum.Medium)
            {
                System.Diagnostics.Debug.Fail(item.PrintMessage(true));
            }
        }

        #region Critical Calls

        /// <summary>
        /// Check condition, if true, report a NotImplementedCritical condition.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="parameters"></param>
        [Obsolete]
        public static void NotImplementedCriticalIf(bool condition, params string[] parameters)
        {
            if (condition == false)
            {
                throw new NotImplementedException("Operation not supported.");
            }
        }

        /// <summary>
        /// Throws a NotImplementedException exception.
        /// </summary>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void NotExpectedCritical(params string[] parameters)
        {
            throw new NotImplementedException("This call was not expected [" + CommonHelper.ParamsToString(parameters) + "].");
        }

        /// <summary>
        /// Report a piece of code is not implemented, and missing functionality is critical to operation.
        /// </summary>
        /// <param name="parameters"></param>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void NotImplementedCritical(params string[] parameters)
        {
            throw new NotImplementedException("The calling method is not implemented [" + CommonHelper.ParamsToString(parameters) + "].");
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameters"></param>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void NotSupported(params string[] parameters)
        {
            throw new NotImplementedException("The calling method is not supported [" + CommonHelper.ParamsToString(parameters) + "].");
        }

        /// <summary>
        /// Report an invalid call.
        /// </summary>
        /// <param name="parameters"></param>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void InvalidCall(params string[] parameters)
        {
            throw new Exception("The calling method is not valid to call [" + CommonHelper.ParamsToString(parameters) + "].");
        }

        /// <summary>
        /// Chech condition, if true, throw an exception with parameters message.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="parameters"></param>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void ThrowIf(bool condition, params string[] parameters)
        {
            if (condition == false)
            {
                Throw(parameters);
            }
        }

        /// <summary>
        /// Throw a general exception with parameters as message.
        /// </summary>
        /// <param name="parameters"></param>
        [Obsolete("Combines badly with modules that need to use Diagnostics under #ifdef clauses.")]
        public static void Throw(params string[] parameters)
        {
            throw new Exception(CommonHelper.ParamsToString(parameters));
        }

        #endregion

        #region Tracing

        /// <summary>
        /// Report a piece of code is not implemented.
        /// </summary>
        /// <param name="parameters"></param>
        public static void NotImplementedError(params string[] parameters)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Error("Error: Not Implemented [" + CommonHelper.ParamsToString(parameters) + "]");
            }
        }

        /// <summary>
        /// Report a piece of code is not implemented, however missing functionality is not critical to operation.
        /// </summary>
        /// <param name="parameters"></param>
        public static void NotImplementedWarning(params string[] parameters)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Warning("Warning: Not Implemented [" + CommonHelper.ParamsToString(parameters) + "]");
            }
        }

        /// <summary>
        /// Submit an error if condition is met.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="errorMessage"></param>
        public static void ErrorIf(bool condition)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.Error(string.Empty);
                }
                
            }
        }

        /// <summary>
        /// If the conditions is met, set error with specified message.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="errorMessage"></param>
        public static void ErrorIf(bool condition, string errorMessage)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.Error(errorMessage);
                }
            }
        }

        /// <summary>
        /// Check given condition, if true, report operation error with given message.
        /// Operation errors are a lighter version of a error, and may be expected to 
        /// occur during normal operation of the application (for. ex. a given non critical 
        /// resource was not retrieved, operation has timed out etc.)
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="errorMessage"></param>
        public static void OperationErrorIf(bool condition, string errorMessage)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.OperationError(errorMessage);
                }
            }
        }

        /// <summary>
        /// Chech given condition, if false, report operation warning with given message.
        /// Operation warnings are a lighter version of a warning, and may be expected to 
        /// occur during normal operaiton of the application.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="message"></param>
        public static void OperationWarningIf(bool condition, string message)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.OperationWarning(message);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void OperationWarningIf(bool condition, string message, TracerItem.PriorityEnum priority)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.OperationWarning(message, priority);
                }
            }
        }

        /// <summary>
        /// Check condition and report a warning, if condition met.
        /// Warnings serve to notify that something in operation of application has gone
        /// wrong, however the error is not critical.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="parameters"></param>
        public static void WarningIf(bool condition, params string[] parameters)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.Warning("Warning: " + CommonHelper.ParamsToString(parameters));
                }
            }
        }

        /// <summary>
        /// Will report only if condition fails.
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="reportMessage"></param>
        public static void InfoIf(bool condition, string reportMessage)
        {
            if (condition)
            {
                TracerItemBuilderEx tracerBuilder = _tracerBuilder;
                if (tracerBuilder != null)
                {
                    tracerBuilder.Info(reportMessage);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void Debug(string reportMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Debug(reportMessage);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void Debug(string reportMessage, Exception exception)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Debug(reportMessage, exception);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void TraceFast(string reportMessage, TracerItem.TypeEnum type, TracerItem.ExtendedTypeEnum extendedType)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.TraceFast(type, extendedType, reportMessage);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void Info(string reportMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Info(reportMessage);
            }
        }

        /// <summary>
        /// Report a simplme message to the report management system.
        /// </summary>
        /// <param name="reportMessage"></param>
        public static void Info(string reportMessage, TracerItem.PriorityEnum priority)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Info(reportMessage, priority);
            }
        }

        /// <summary>
        /// Report operation warning; it is a normal occurence in the work of the system. It can be caused
        /// for example by the lack of access to a resource or some error in a data stream.
        /// </summary>
        /// <param name="warningMessage"></param>
        public static void OperationWarning(string warningMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.OperationWarning(warningMessage);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void OperationWarning(string warningMessage, TracerItem.PriorityEnum priority)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.OperationWarning(warningMessage, priority);
            }
        }

        
        /// <summary>
        /// A Warning notifies that in some part of the systems operation a recovarable error has occured.
        /// </summary>
        /// <param name="warningMessage"></param>
        public static void Warning(string warningMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Warning(warningMessage);
            }
        }

        /// <summary>
        /// Report operation error with exception.
        /// </summary>
        /// <param name="ex"></param>
        public static void OperationError(string errorDetails, Exception exception)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.OperationError(errorDetails, exception);
            }
        }

        /// <summary>
        /// Report operation error; it is a lighter, more common version of a error, and may be expected to 
        /// occur during normal operation of the application (for. ex. a given non critical 
        /// resource was not retrieved, operation has timed out etc.)
        /// </summary>
        /// <param name="errorMessage"></param>
        public static void OperationError(string errorMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.OperationError(errorMessage, TracerItem.PriorityEnum.High);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void OperationError(string errorMessage, TracerItem.PriorityEnum priority)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.OperationError(errorMessage, priority);
            }
        }

        /// <summary>
        /// Report an serious error. Those errors are usually a sign something in the work
        /// of the application has gone seriously wrong, and operation can not continue
        /// properly (for ex. unexpected exception, access to critical resources etc.)
        /// </summary>
        /// <param name="errorMessage"></param>
        public static void Error(string errorMessage)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Error(errorMessage);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="errorMessage"></param>
        public static void Error(string errorMessage, TracerItem.PriorityEnum priority)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Error(errorMessage, priority);
            }
        }

        /// <summary>
        /// Helper, redefine with exception consumption.
        /// </summary>
        /// <param name="errorMessage"></param>
        /// <param name="exception"></param>
        public static void Error(string errorMessage, Exception exception)
        {
            TracerItemBuilderEx tracerBuilder = _tracerBuilder;
            if (tracerBuilder != null)
            {
                tracerBuilder.Error(errorMessage, exception);
            }
        }

           
        #endregion
    }
}
